#!/bin/bash
#
# Author: Joshua Chen
# Date: 2014-08-03
# Location: Shenzhen
# Description: generate a service control script for a specific mysql config file
# based on the original script 
#

# functions

help()
{
    echo "Usage: $(basename $0) <config file>" >&2
}

generate_script()
{
cat > $target << 'GENERATE-SCRIPT'
#!/bin/sh
#
# mysqld	This shell script takes care of starting and stopping
#		the MySQL subsystem (mysqld).
#
# chkconfig: - 64 36
# description:	MySQL database server.
# processname: mysqld
# config: /etc/my.cnf
# pidfile: /var/run/mysqld/mysqld.pid

###################################################################
#                                                                 #
#  Author: Joshua Chen                                            #
#  Date: 2014-08-03                                               #
#  Location: ShenZhen                                             #
#  Description:                                                   #
#    to suit the needs of running multiple instances,             #
#    this script shall be generated by genmysqlscript             #
#                                                                 #
###################################################################



# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network


basedir="{{BASEDIR}}"
mysqld_safe="{{MYSQLD_SAFE}}"
mysqladmin="{{MYSQLADMIN}}"
installdb="{{INSTALLDB}}"
inst="{{INSTANCE}}"
pdefault="{{MYPRINTDEFAULT}}"
config_file="{{CONFIGFILE}}"

# Set timeouts here so they can be overridden from /etc/sysconfig/${inst}
STARTTIMEOUT=120
STOPTIMEOUT=60

[ -e /etc/sysconfig/${inst} ] && . /etc/sysconfig/${inst}

lockfile=/var/lock/subsys/${inst}


# extract value of a MySQL option from config files
# Usage: get_mysql_option SECTION VARNAME DEFAULT
# result is returned in $result
# We use my_print_defaults which prints all options from multiple files,
# with the more specific ones later; hence take the last match.
get_mysql_option(){
	result=`${pdefault} -c $config_file $1 | sed -n "s/^--$2=//p" | tail -n 1`
	if [ -z "$result" ]; then
	    # not found, use default
	    result="$3"
	fi
}

# read the settings from the config file
get_mysql_option "mysqld mysqld_safe" datadir "/var/lib/mysql"
datadir="$result"

get_mysql_option "mysqld mysqld_safe" socket "$datadir/mysql.sock"
socketfile="$result"
test "${socketfile/\//}" = "$socketfile" && socketfile="${datadir}/${socketfile}"

get_mysql_option "mysqld mysqld_safe" log-error "/var/log/mysqld.log"
errlogfile="$result"
test "${errlogfile/\//}" = "$errlogfile" && errlogfile="${datadir}/${errlogfile}"

get_mysql_option "mysqld mysqld_safe" log-bin "${datadir}/binlog"
binlog="$result"

get_mysql_option "mysqld mysqld_safe" pid-file "/var/run/mysqld/mysqld.pid"
mypidfile="$result"
test "${mypidfile/\//}" = "$mypidfile" && mypidfile="${datadir}/${mypidfile}"

get_mysql_option "mysqld mysqld_safe" user mysql
user="$result"

get_mysql_option "mysqld mysqld_safe" basedir "$basedir"
basedir="$result"

get_mysql_option "mysqld mysqld_safe" innodb_log_group_home_dir "$datadir"
innodb_log_group_home_dir="$result"

get_mysql_option "mysqld mysqld_safe" innodb_data_home_dir "$datadir"
innodb_data_home_dir="$result"

get_mysql_option "mysqld mysqld_safe" relay-log "$datadir"
relay_log_dir="$(dirname $result)"


isrunning()
{
    RESPONSE=`$mysqladmin --socket="$socketfile" --user=UNKNOWN_MYSQL_USER ping 2>&1`
    if [ $? = 0 ]; then
        ret=0
    elif echo "$RESPONSE" | grep -q "Access denied for user"; then
        ret=0
    else
        ret=1
    fi
    return $ret
}

prepare_dirs()
{
    # fail if $user not exists
    if ! grep -qE "^${user}:" /etc/passwd; then
        echo "user $user not exists" >&2
        exit 1
    fi

    for dir in $datadir $(dirname $socketfile) $(dirname $errlogfile) \
               $(dirname $mypidfile) $(dirname $binlog) $innodb_log_group_home_dir \
               $innodb_data_home_dir $relay_log_dir
    do
        if [ "$dir" != "." ];then
            if [ ! -e "$dir" -a ! -h "$dir" ]; then
                mkdir -pv "$dir" || exit 1
            fi
            chown ${user}:${user} "$dir"
            chmod 0755 "$dir"
            [ -x /sbin/restorecon ] && /sbin/restorecon "$dir"
        fi
    done
}

start(){
    [ -x $mysqld_safe ] || exit 5

    if isrunning; then
        # already running, do nothing
        action $"Starting $inst: " /bin/true
        ret=0
    else
    	# prepare for start
        if [ ! -d "$datadir/mysql" ] ; then
            # First, make sure $datadir and other directories are there with correct permissions
            prepare_dirs

            # Now create the database
            action $"Initializing MySQL database: " ${installdb} --defaults-file="$config_file" --basedir="$basedir"
            ret=$?
            chown -R ${user}:${user} "$datadir"
            if [ $ret -ne 0 ] ; then
                return $ret
            fi
        fi
        chown ${user}:${user} "$datadir"
        chmod 0755 "$datadir"

        touch "$errlogfile"
        chown ${user}:${user} "$errlogfile" 
        chmod 0640 "$errlogfile"
        [ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile"

        # Pass all the options determined above, to ensure consistent behavior.
        # In many cases mysqld_safe would arrive at the same conclusions anyway
        # but we need to be sure.  (An exception is that we don't force the
        # log-error setting, since this script doesn't really depend on that,
        # and some users might prefer to configure logging to syslog.)
        # Note: set --basedir to prevent probes that might trigger SELinux
        # alarms, per bug #547485
        $mysqld_safe --defaults-file=$config_file --basedir="$basedir" >/dev/null 2>&1 &
        safe_pid=$!

        # Spin for a maximum of N seconds waiting for the server to come up;
        # exit the loop immediately if mysqld_safe process disappears.
        # Rather than assuming we know a valid username, accept an "access
        # denied" response as meaning the server is functioning.
        ret=0
        TIMEOUT="$STARTTIMEOUT"
        while [ $TIMEOUT -gt 0 ]
        do
            isrunning && break;
            if ! /bin/kill -0 $safe_pid 2>/dev/null; then
                echo "MySQL Daemon failed to start."
                ret=1
                break
            fi
            sleep 1
            let TIMEOUT=${TIMEOUT}-1
        done
        if [ $TIMEOUT -eq 0 ]; then
            echo "Timeout error occurred trying to start MySQL Daemon."
            ret=1
        fi
        if [ $ret -eq 0 ]; then
            action $"Starting $inst: " /bin/true
            touch $lockfile
        else
            action $"Starting $inst: " /bin/false
        fi
    fi
    return $ret
}

stop(){
	if [ ! -f "$mypidfile" ]; then
	    # not running; per LSB standards this is "ok"
	    action $"Stopping $inst: " /bin/true
	    return 0
	fi

	MYSQLPID=`cat "$mypidfile"`
	if [ -n "$MYSQLPID" ]; then
	    /bin/kill "$MYSQLPID" &>/dev/null
	    ret=$?
	    if [ $ret -eq 0 ]; then
            TIMEOUT="$STOPTIMEOUT"
            while [ $TIMEOUT -gt 0 ]
            do
                /bin/kill -0 "$MYSQLPID" >/dev/null 2>&1 || break
                sleep 1
                let TIMEOUT=${TIMEOUT}-1
            done
            if [ $TIMEOUT -eq 0 ]; then
                echo "Timeout error occurred trying to stop MySQL Daemon."
                ret=1
                action $"Stopping $inst: " /bin/false
            else
                rm -f $lockfile
                rm -f "$socketfile"
                action $"Stopping $inst: " /bin/true
            fi
	    else
		    action $"Stopping $inst: " /bin/false
	    fi
	else
	    # failed to read pidfile, probably insufficient permissions
	    action $"Stopping $inst: " /bin/false
	    ret=4
	fi
	return $ret
}
 
restart(){
    stop
    start
}

condrestart(){
    [ -e $lockfile ] && restart || :
}


# See how we were called.
case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  status)
    status -p "$mypidfile" $inst
    ;;
  restart)
    restart
    ;;
  condrestart|try-restart)
    condrestart
    ;;
  force-reload)
    restart
    ;;
  *)
    echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|force-reload}"
    exit 2
esac

exit $?
GENERATE-SCRIPT
}

getinput()
{
    echo -n "$1 [$2]: "
    read result
    if [ -z "$result" ];then
        result=$2
    fi
}

get_instance()
{
    while true
    do
        getinput "What name for this instance" "mysqld"
        if [ -e /etc/init.d/$result ];then
            echo "$result already exists, choose another one" >&2
        else
            break
        fi
    done
}

get_basedir()
{
    while true
    do
        getinput "Where is the base dir (installation prefix)" "/usr"
        if [ ! -e $result/bin/mysqld_safe ];then
            echo "$result doesn't seem to be a valid base dir" >&2
        else
            break
        fi
    done
}

getexec()
{
    while true
    do
        getinput "$1" "$2"
        if [ ! -f "$result" -o ! -x "$result" ];then
            echo "$result not exists or is not executable" >&2
        else
            break
        fi
    done
}

# config file must be specified and exist
if [ -z "$1" ];then
    help
    exit 1
fi
if [ ! -e "$1" ];then
    echo "$1 not exists" >&2
    exit 1
fi

# determine the absolute path name of the config file
if [ "${1#/}" = "$1" ];then
    config_file="$(cd $(dirname $1); pwd)/$(basename $1)"
else
    config_file="$1"
fi

get_instance
inst="$result"
target="/etc/init.d/$inst"

get_basedir
basedir=$result

getexec "Where is the mysqld_safe" "$basedir/bin/mysqld_safe"
mysqld_safe="$result"

getexec "Where is the mysqladmin" "$basedir/bin/mysqladmin"
mysqladmin="$result"

getexec "Where is the mysql_install_db" "$(find $basedir -name mysql_install_db)"
installdb="$result"

getexec "Where is the my_print_defaults" "$basedir/bin/my_print_defaults"
pdefault="$result"

# create the target script
generate_script

# customize the script
sed -i \
-e "s@{{BASEDIR}}@$basedir@g" \
-e "s@{{MYSQLD_SAFE}}@$mysqld_safe@g" \
-e "s@{{MYSQLADMIN}}@$mysqladmin@g" \
-e "s@{{INSTALLDB}}@$installdb@g" \
-e "s@{{INSTANCE}}@$inst@g" \
-e "s@{{MYPRINTDEFAULT}}@$pdefault@g" \
-e "s@{{CONFIGFILE}}@$config_file@g" \
$target

chmod 755 $target
chkconfig --add $inst

